package cldlockc;

use cld_client;
use File::Basename;
use Sys::Hostname;

$cldlockc::last_error=undef;
$cldlockc::last_rc=0;

sub new {
my $proto=shift;
my $class=ref($proto) || $proto;
my $self;
my $conn;
my %args=@_;

	if(!exists($args{PORT}) || !exists($args{KEY})) {
		$cldlockc::last_error="Missing mandatory argument.";
		$cldlockc::last_rc=1;
		return undef;
	}

	$self={};
	$conn=cld_client->new(
			PORT => $args{PORT},
			INET => "127.0.0.1",
			KEY  => $args{KEY});
	if(!defined($conn)) {
		$cldlockc::last_error="Unable to client connection connection object.";
		$cldlockc::last_rc=2;
	}
	$self->{CONN}=$conn;

	if(exists($args{CHECK}) && defined($args{CHECK}) && $args{CHECK}) {
		# Attempt to get a connection to the lock daemon and die if we can not.

		$resp=$self->{CONN}->send_msg(
			MSG => "LIST_LOCK", TIMEOUT => 10);
		$self->{CONN}->close_session;
		
		if(!defined($resp)) {
			::errmsg("Unable to read from lock daemon.");
			return undef;
		}
	}
	bless($self,$class);
	return $self;
}

#########################################################################
# This routine attempts to acquire a specified lock. It will return 	#
# (1,"OK") or (0,"Error").						#
# The following arguments are expected:					#
# PID		: Current process ID					#
# CPROC		: Label for the current process				#
# HOLD  	: Length of time to grab lock for			#
# LOCK		: Label of lock to grab					#
#									#
# Optionally the following arguments can be used:			#
# MAXWAIT	: Maximum length of time in seconds to waitto 		#
#		  acquire the lock [default is 30 seoncds.]		#
# INTERVAL	: How often to attempt to acquire the lock - the	#
#		  default is .5 seconds.				#
#########################################################################

sub acquire {
my $self=shift;
my %args=@_;
my $stime=time;
my $maxtime=30;
my $interval=0.5;
my ($hold,$lock,$cpid,$cproc);

	if(!exists($args{PID}) || !exists($args{CPROC}) 
		|| !exists($args{LOCK}) || !exists($args{HOLD})) {
		return(0,"Missing one or more mandatory arguments (PID,LOCK,CPROC,HOLD)");
	}
	$lock=$args{LOCK};
	$cpid=$args{PID};
	$cproc=$args{CPROC};
	$maxtime=$args{MAXWAIT} if exists($args{MAXWAIT});
	$interval=$args{INTERVAL} if exists($args{INTERVAL});
	$hold=$args{HOLD};

	if(!defined($hold) || !defined($lock) || !defined($cpid) || !defined($cproc)) {
		return(0,"Mandatory variable passed, but is undefined.");
	}

	while(time < $stime+$maxtime) {
		my $resp;

		$resp=$self->{CONN}->send_msg(
			MSG => "GET_LOCK TYPE=$lock TIME=$hold CPROC=$cproc CPID=$cpid",
			TIMEOUT => 2);
		$self->{CONN}->close_session;
			
		if(defined($resp)) {
			if($resp eq "OK") {
				return(1,"OK");
			}
			@w=split(/\s+/,$resp);
			if($w[0] eq "FAIL") {
				return(1,join(" ",@w[1..$#w]));
			}
			#################################################
			# Otherwise in use or wait for deamon to answer	#
			# next time we are run.				#
			#################################################
		}
		select(undef,undef,undef,$interval);
	}
	return(1,"Unable to acquire lock $lock in $maxtime seconds.");
}

#########################################################################
# This routine attempts to release a specified lock. It will return 	#
# (1,"OK") or (0,"Error"). 						#
# Note: Locks are force released automatically if they exceed there 	#
#	own timeout.							#
#									#
# The following arguments are expected:					#
# PID		: Current process ID					#
# CPROC		: Label for the current process				#
# LOCK		: The lock type to release				#
#									#
# Optionally the following arguments can be used:			#
# MAXWAIT	: Maximum length of time in seconds to wait to 		#
#		  release the lock [default is 5 seoncds.]		#
# INTERVAL	: How often to attempt to release the lock - the	#
#		  default is .5 seconds.				#
#########################################################################

sub release {
my $self=shift;
my %args=@_;
my ($lock,$cpid,$cproc);
my $stime=time;
my $maxtime=5;
my $interval=0.5;

	if( (!exists($args{PID}) && !exists($args{CPROC}))
		|| !exists($args{LOCK})) {
		return(0,"Missing one or more mandatory arguments (PID|CPROC,LOCK)");
	}
	$lock=$args{LOCK};
	$cpid=$args{PID} if exists($args{PID});
	$cproc=$args{CPROC} if exists($args{CPROC});
	$maxtime=$args{MAXWAIT} if exists($args{MAXWAIT});
	$interval=$args{INTERVAL} if exists($args{INTERVAL});

	if(!defined($lock) || (!defined($cpid) && !defined($cproc))) {
		return(0,"Mandatory variable passed, but is undefined.");
	}

	$cmd="RELEASE_LOCK TYPE=$lock ";
	$cmd.="CPROC=$cproc " if defined($cproc);
	$cmd.="CPID=$cpid" if defined($cpid);
	while(time < $stime+$maxtime) {
		my $resp;

		$resp=$self->{CONN}->send_msg(MSG => $cmd, TIMEOUT => 2);
		$self->{CONN}->close_session;

		if(defined($resp)) {
			if($resp eq "OK") {
				return(1,"OK");
			}
			@w=split(/\s+/,$resp);
			return(1,join(" ",@w[1..$#w]));
			#################################################
			# Otherwise in use or wait for deamon to answer	#
			# next time we are run.				#
			#################################################
		}
		select(undef,undef,undef,$interval);
	}
	return(1,"Unable to release lock $lock in $maxtime seconds.");
}

sub listlocks {
my $self=shift;
my $maxtime=5;
my $interval=0.5;
my %args=@_;
my $stime=time;

	$maxtime=$args{MAXWAIT} if exists($args{MAXWAIT});
	$interval=$args{INTERVAL} if exists($args{INTERVAL});

	$cmd="LIST_LOCK";
	while(time < $stime+$maxtime) {
		my $resp;

		$resp=$self->{CONN}->send_msg(MSG => $cmd, TIMEOUT => 2);
		$self->{CONN}->close_session;

		if(defined($resp)) {
			@w=split(/\s+/,$resp);
			if($w[0] eq "OK") {
				$resp =~ s/^OK\s+//;
				return(0,"$resp");
			}
			return(1,join(" ",@w[1..$#w]));
			#################################################
			# Otherwise in use or wait for deamon to answer	#
			# next time we are run.				#
			#################################################
		}
		select(undef,undef,undef,$interval);
	}
	return(1,"Unable to get lock list in $maxtime seconds.");
}

sub abort {
my $self=shift;
	$self->{CONN}->send_msg(MSG => "ABORT", TIMEOUT => 5);
	$self->{CONN}->close_session;
}

1;

